import View from './components/view'
import Link from './components/link'

export let _Vue

export function install(Vue) {
    //保证只安装一次
    if (install.installed && _Vue === Vue) return
    install.installed = true

    _Vue = Vue

    const isDef = v => v !== undefined

    const registerInstance = (vm, callVal) => {
        let i = vm.$options._parentVnode
        //@todo registerRouteInstance方法的作用是什么？
        //猜测：registerRouteInstance方法是在router-view组件中添加的， 感觉该方法用于保存
        //与当前router-view关联的vue实例对象
        if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
            i(vm, callVal)
        }
    }

    Vue.mixin({
        beforeCreate() {
            //说明当前组件是添加路由对象的根对象，
            //只会在路由根对象上创建_router和_route两个属性
            if (isDef(this.$options.router)) {
                //_routerRoot用于保存添加路由对象的根组件对象
                this._routerRoot = this
                //路由对象
                this._router = this.$options.router
                this._router.init(this)
                //_route的作用是什么？
                //答：this._router.history.current指向当前路由信息对象
                Vue.util.defineReactive(this, '_route', this._router.history.current)
            } else {
                //如果不是根组件，则会直接将存储着路由对象的vue实例保存下来
                //'|| this'的原因是：如果Vue实例不是通过根组件创建的，而是通过new Vue()的方式创建的，
                //并且没有'|| this'，则在访问$router和$route属性时，就会报空指针异常
                this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
            }
            registerInstance(this, this)
        },
        destroyed() {
            registerInstance(this)
        }
    })

    Object.defineProperty(Vue.prototype, '$router', {
        get() {
            return this._routerRoot._router
        }
    })

    Object.defineProperty(Vue.prototype, '$route', {
        get() {
            return this._routerRoot._route
        }
    })

    Vue.component('RouterView', View)
    Vue.component('RouterLink', Link)

    const strats = Vue.config.optionMergeStrategies
    // use the same hook merging strategy for route hooks
    strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}
